<?php

/**
 * Session Object
 *
 * Provides a standard interface for dealing with sessions.
 *
 * Warlock is free software. This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses.
 *
 * @package    warlock
 * @author     David Cole <neophyte@sourcetutor.com>
 * @license    GNU/GPL v2
 */

// Object Dependencies
using('Library.Patterns.Registry');
using('Engine.Observer');

class Session extends Registry
{
    /**
     * Session Fingerprint
     *
     * Contains the fingerprint of the current page view
     * used as a means of identification and security
     *
     * @var unknown_type
     */
    var $_Fingerprint;

    /**
     * Data Access Layer
     *
     * @var DAL
     */
    var $_DAL;

    /**#@+
     * Required Core Objects
     *
     * These are references to the core objects required by this
     * class.
     *
     * @access private
     * @var    object
     */
    var $_Error;
    var $_Observer;
    var $_Config;
    var $_Profilier;
    /**#@-*/

    /**
     * Initialise User Object
     *
     * Performs general object startup tasks such as getting instances to the required
     * core objects, initalising the php session and attempting to load any saved user
     * sessions.
     *
     * @return void
     * @access public
     */
    function __construct()
    {
        // Add class to the vault
        Vault::Add('Session', &$this);

        // Call the registry constructor
        parent::__construct();

        // Instance required objects
        $this->_Error    = &Vault::Get('Debug_Error');
        $this->_Profiler = &Vault::Get('Debug_Profiling');
    	$this->_Observer = &Vault::Get('Observer');
    	$this->_Config   = &Vault::Get('Config');
    	$this->_DAL      = &Vault::Get('DAL');


        /*
         * Set session settings and perfom any general startup tasks
         */

        $t = $this->_Profiler->Start('Establish Session Data');

        // Session fingerprint
        $this->_Fingerprint = $this->_CreateFingerPrint();

        // Initialise the PHP Session
        session_set_cookie_params(0, '/');
        session_start();

        // Make the registry a reference of the session super global
        $this->_registry =& $_SESSION;

        if (!isset($_SESSION['warlock']['browser-session']))
        {
            $this->_Error->Log('Session :: No active session, initialising blank session.', W_LOG_DEBUG);
            $this->Clear();

            /*
             * No active PHP session detected so lets try and load the warlock session
             * failing that create a new session.
             */

            if (isset($_COOKIE['WSESSID']) && !empty($_COOKIE['WSESSID']))
            {
            	$this->_Error->Log('Session :: Looking for saved session.', W_LOG_DEBUG);
            	
                if ($client_session = $this->_DAL->Select('session', $_COOKIE['WSESSID']))
                {
                    $_SESSION = unserialize(base64_decode($client_session->data));
                    $this->_Error->Log('Session :: Warlock Session Data Loaded', W_LOG_DEBUG);
                }
            }
        }

        // Ensure the fingerpint remains the same within an active session
        if ($_SESSION['warlock']['browser-session']['fingerprint'] != $this->_Fingerprint)
        {
            $this->_Error->Log('Session :: Fingerprints dont match, creating blank session.', W_LOG_DEBUG);
            $this->Clear();
        }
        else
            $this->_UpdateSessionData();

        // Hook the onExit event
        $this->_Observer->AddListener('onExit', array(&$this, 'Save'));

        $this->_Profiler->Stop($t);
    }


    /**
     * Clear Session
     *
     * Creates an initial empty session.
     *
     * @return void
     * @access public
     */
    function Clear()
    {
        // Clear the session
        $_SESSION = array();

        // Set the defaults
        $_SESSION['warlock']['browser-session'] = array('fingerprint'  => $this->_CreateFingerPrint(),
                                                        'page_views'   => 1,
                                                        'start_page'   => $_SERVER['REQUEST_URI'],
                                                        'start_date'   => time(),
                                                        'current_page' => $_SERVER['REQUEST_URI'],
                                                        'current_date' => time() );
    }

    /**
     * Save User Session
     *
     * Attempts to save the user session, typically only used with logged in users.
     *
     * @return void
     * @access public
     */
    function Save()
    {
        $this->_User = &Vault::Get('User');

    	if($this->_User->IsLoggedIn())
    	{
    	    // Update/Create the Users Session Record
    	    if($this->_DAL->Update('session', array('data' => base64_encode(serialize($_SESSION))), $this->_Fingerprint))
    	        $this->_Error->Log('Session :: Successfully Updated Session \''.$_SESSION['browser-session']['fingerprint'].'\'', W_LOG_DEBUG);
    	    else
    	    {
    	        $this->_Error->Log('Session :: Attempting to create new session record \''.$this->_Fingerprint.'\'', W_LOG_DEBUG);

    	        if (!$this->_DAL->Insert('session', array('id' => $this->_Fingerprint, 'session' => base64_encode(serialize($_SESSION)), 'uid' => $this->_User->DataObject->id)))
    	        {
    	            $this->_Error->Log('Session :: Error Creating Session Record', W_LOG_DEBUG);
    	            return false;
    	        }
    	    }

			// Set session cookie
			setcookie ('WSESSID', $this->_Fingerprint, time() + (86400 * $this->_Config->Get('session-expire')), '/');
			$this->_Error->Log('Session :: Setting Warlock Session Cookie', W_LOG_DEBUG);
    	}
    }

    /**
     * Update Session Data
     *
     * Increments the session counters and sets the current page,
     * should only be called once per page.
     *
     * @return void
     * @access private
     */
    function _UpdateSessionData()
    {
		$_SESSION['warlock']['browser-session']['page_views']++;
		$_SESSION['warlock']['browser-session']['current_page'] = $_SERVER['REQUEST_URI'];
		$_SESSION['warlock']['browser-session']['current_date'] = time();
    }

    /**
     * Get User IP
     *
     * Attempts to determine the IP of the user currently browsing the site, slightly
     * hacking due to some ISP's changing IP's mid session like AOL.
     *
     * @return void
     * @access private
     */
	function _CreateFingerPrint()
    {
        return md5(((isset($_SERVER['HTTP_X_FORWARDED_FOR']))?$_SERVER['HTTP_X_FORWARDED_FOR']:$_SERVER['REMOTE_ADDR']).$_SERVER['HTTP_USER_AGENT']);
    }
}
?>